/**
 * Copyright 2005 SIB Framework

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */



/**
 * this class compress files to a zip file
 */
package org.sibframework.utils;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;




public class ZipTool {

	/**
	 * the buffer size when write data.
	 */
	private static final int BUFFER = 4096;

	/**
	 * a buffer for dual data
	 */
	private byte[] data = new byte[BUFFER];

	/**
	 * input stream
	 */
	private BufferedInputStream origin = null;

	/**
	 * @param srcs source file names to compress, String arrary.
	 * @param target target zip file name.
	 * @return ture/false.
	 */

	public final boolean compress(final String[] srcs, final String target) {
		File[] files = new File[srcs.length];
		for (int j = 0; j < srcs.length; j++) {
			File f = new File(srcs[j]);
			files[j] = f;
		}
		return this.compress(files, new File(target));
	}
	public final boolean compress(final File[] srcs, final File target) {
		try {
			FileOutputStream dest = new FileOutputStream(target);
			ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
					dest));
			// out.setMethod(ZipOutputStream.DEFLATED);
			// get a list of files from current directory
			for (int j = 0; j < srcs.length; j++) {
				File f = srcs[j];
				if (!f.isDirectory()) {
					invokeFile(f, out, "");
				} else {
					invokeDir(f, out, "");
				}
			}
/*
			//operator plugin
			if (fileHandlers == null) {
				out.close();
				return true;
			}
			for (int i = 0; i < fileHandlers.size(); i++) {
				FileHandler fh = (FileHandler) fileHandlers.get(i);
				try {
					File file = fh.result();
					invokeFile(file, out, "");
				} catch (Exception e) {
					//exception catch here, don't throw.
					//When plug-in error, keep the compress process continue.
					System.out.print("plugin result error in zip operator.");
					e.printStackTrace();
				}
			}
*/			out.close();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	public void extract(File zipFile, File project) {
		if (!zipFile.exists() || !zipFile.isFile()) {
			return;
		}
		try {
			FileInputStream fis = new FileInputStream(zipFile);
			extract(fis, project);
			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
/*
	public void extractResource(File zipFile, IProject project) {
		if (!zipFile.exists() || !zipFile.isFile()) {
			return;
		}
		try {
			FileInputStream fis = new FileInputStream(zipFile);
			ZipInputStream zis;
			zis = new ZipInputStream(fis);
			for (ZipEntry entry = zis.getNextEntry();entry != null;entry = zis.getNextEntry()) {
				if (entry.getName().equalsIgnoreCase(".project")) {
					continue;
				}
				//System.out.println(entry.getName());
				if (entry.isDirectory()) {
					project.getFolder(entry.getName()).create(true, false, null);
					File file = new File(dir.getAbsolutePath() + "\\" +  entry.getName());
					file.mkdir();
				} else {
					
					project.getFile(entry.getName()).create(new BufferedInputStream(zis){public void close() throws IOException {}}, true, null);
					File file = new File(dir.getAbsolutePath() + "\\" + entry.getName());
					if (!file.getParentFile().exists()) {
						file.getParentFile().mkdir();
					}
					BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(file));
					int count;
					while ((count = zis.read(data, 0, BUFFER)) != -1) {
						dest.write(data, 0, count);
					}
					dest.close();
				}
			}
			zis.close();
			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
	*/
	public void extract(InputStream zipFile, File dir) {
		if (!dir.isDirectory()) {
			return;
		}
		ZipInputStream zis;
		try {
			zis = new ZipInputStream(zipFile);
			for (ZipEntry entry = zis.getNextEntry();entry != null;entry = zis.getNextEntry()) {
				//System.out.println(entry.getName());
				if (entry.isDirectory()) {
					File file = new File(dir.getAbsolutePath() + "\\" +  entry.getName());
					file.mkdir();
				} else {
					File file = new File(dir.getAbsolutePath() + "\\" + entry.getName());
					if (!file.getParentFile().exists()) {
						file.getParentFile().mkdir();
					}
					BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(file));
					int count;
					while ((count = zis.read(data, 0, BUFFER)) != -1) {
						dest.write(data, 0, count);
					}
					dest.close();
				}
			}
			zis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public InputStream readFile(InputStream zipFile, String filename) throws IOException {
		ZipInputStream zis = new ZipInputStream(zipFile);
		ZipEntry entry = zis.getNextEntry();
		while (entry != null && (entry.isDirectory() || !entry.getName().equalsIgnoreCase(filename))) {
			entry = zis.getNextEntry();
		}
		if (entry == null) {
			return null;
		}
		return zis;
	}

	public InputStream readFile(File srcZip, String filename) throws IOException {
		ZipInputStream zis = new ZipInputStream(new FileInputStream(srcZip));
		ZipEntry entry = zis.getNextEntry();
		while (entry != null && (entry.isDirectory() || !entry.getName().equalsIgnoreCase(filename))) {
			entry = zis.getNextEntry();
		}
		if (entry == null) {
			return null;
		}
		return zis;
	}
	
	/**
	 * @param file directory file to compress.
	 * @param out outputstream to target zip file.
	 * @param parent parent path.
	 * @throws IOException io exceprion
	 */
	private void invokeDir(final File file, final ZipOutputStream out,
			final String parent) throws IOException {

		String entryPath = parent + file.getName() + "/";
		//System.out.println("Adding dir: " + file.getName());
		ZipEntry entry = new ZipEntry(entryPath);
		out.putNextEntry(entry);

		File[] files = file.listFiles();

		for (int i = 0; i < files.length; i++) {
			if (!files[i].isDirectory()) {
				invokeFile(files[i], out, entryPath);
			} else {
				invokeDir(files[i], out, entryPath);
			}
		}

	}

	/**
	 * @param file file to compress.
	 * @param out outputstream to target zip file.
	 * @param parent parent path.
	 * @throws IOException io exceprion
	 */
	private void invokeFile(final File file, final ZipOutputStream out,
			final String parent) throws IOException {
		//System.out.println("Adding file: " + file);
		FileInputStream fi = new FileInputStream(file);
		origin = new BufferedInputStream(fi, BUFFER);
		ZipEntry entry = new ZipEntry(parent + file.getName());
		out.putNextEntry(entry);
		int count;
		while ((count = origin.read(data, 0, BUFFER)) != -1) {
			out.write(data, 0, count);
		}
		origin.close();

/*		//operator plugin
		if (fileHandlers == null) {
			return;
		}
		for (int i = 0; i < fileHandlers.size(); i++) {
			FileHandler fh = (FileHandler) fileHandlers.get(i);
			try {
				fh.handle(file);
			} catch (Exception e) {
				System.out.print("plugin.handle error in zip operator.");
				e.printStackTrace();
			}
		}*/
	}

}
